/**
 **********************************************************************************************************************
 * @file       cot_led.c
 * @brief      轻量级LED控制模块实现文件
 *
 * @details
 * 主要功能:
 * 1. LED基本控制：开关、闪烁
 * 2. LED高级控制：呼吸灯、跑马灯、流水灯
 * 3. 支持自定义LED控制序列
 * 4. 支持设置控制次数和结束状态
 * 5. 单个LED控制：开关、闪烁、呼吸灯等
 * 6. 多个LED组合控制：跑马灯、流水灯等
 *
 * 使用步骤:
 * 1. 实现LED控制回调函数(cotLedCtrl_f)
 * 2. 调用cotLed_Init初始化LED控制模块
 * 3. 周期调用cotLed_Ctrl更新LED状态
 * 4. 使用其他接口函数控制LED
 *
 * 主要特点:
 * 1. 非阻塞式设计，适用于裸机和RTOS
 * 2. 移植方便，只需实现LED控制回调函数
 * 3. 支持软件PWM实现呼吸灯效果
 * 4. 灵活的自定义控制接口
 **********************************************************************************************************************
 */

/* Includes ----------------------------------------------------------------------------------------------------------*/
#include "./BSP/LED/cot_led.h"
#include <string.h>
#include <stdarg.h>

/* 呼吸灯软件模拟PWM频率（HZ） */
#define BREATHE_PWM_RATE 50 /* PWM频率50Hz,周期20ms */

/* Private typedef ---------------------------------------------------------------------------------------------------*/
/* Private define ----------------------------------------------------------------------------------------------------*/

/* 呼吸灯PWM周期(ms) = 1000ms/50Hz = 20ms */
#define BREATHE_PWM_PERIOD (1000 / BREATHE_PWM_RATE)

/* Private macro -----------------------------------------------------------------------------------------------------*/

/* 时间计数最大值 */
#define TIME_MAX_VAL (uint32_t)0xffff

/* 时间累加宏,防止溢出 */
#define TIME_ADD(tic, time) (TIME_MAX_VAL - (tic) < (time) ? ((tic) = 0xffff) : (tic += time))

/* 取绝对值 */
#define LED_ABS(a) ((a) > 0 ? (a) : -(a))

/* 设置状态位数组中的连续位 */
#define FILL_STATE_BITS(state, sbit, ebit)           \
    {                                                \
        int bit;                                     \
        for (bit = (sbit); bit < (ebit); bit++)      \
            (state)[bit / 8] |= (0x01 << (bit % 8)); \
    }

/* 设置状态位数组中的单个位 */
#define SET_STATE_BITS(state, bit)               \
    {                                            \
        (state)[bit / 8] |= (0x01 << (bit % 8)); \
    }

/* Private variables -------------------------------------------------------------------------------------------------*/

/* LED配置表指针 */
static cotLedCfg_t *sg_pLedTable = NULL;

/* LED总数 */
static size_t sg_ledNum = 0;

/* Private function prototypes ---------------------------------------------------------------------------------------*/
/* Private function --------------------------------------------------------------------------------------------------*/

/**
 * @brief      LED模块初始化
 *
 * @param[in]  pCfgTable LED配置表指针,包含每个LED的控制回调函数
 * @param[in]  num       LED的总数
 *
 * @note       该函数必须在使用其他LED控制函数前调用
 *             初始化时会清空所有LED的控制状态
 *
 * @retval     0         成功
 * @retval     -1        失败
 */
int cotLed_Init(cotLedCfg_t pCfgTable[], size_t num)
{
    uint8_t led;

    /* 保存LED配置表 */
    sg_pLedTable = pCfgTable;
    sg_ledNum = num;

    /* 初始化所有LED的控制状态 */
    for (led = 0; led < num; led++)
    {
        memset(&sg_pLedTable[led].proc, 0, sizeof(cotLedProc_t));
    }

    return 0;
}

/**
 * @brief      设置LED的亮灭状态
 *
 * @param[in]  led       指定指示灯
 * @param[in]  state     亮灭状态
 *             @arg      COT_LED_ON  LED点亮
 *             @arg      COT_LED_OFF LED熄灭
 *
 * @note       该函数设置LED为固定状态,不会自动改变
 *
 * @retval     0         成功
 * @retval     -1        失败
 */
int cotLed_SetState(led_t led, cotLedState_e state)
{
    /* 参数有效性检查 */
    if (sg_pLedTable == NULL || sg_ledNum == 0 || led >= sg_ledNum)
    {
        return -1;
    }

    /* 设置LED控制参数 */
    sg_pLedTable[led].proc.interval = 100;                                      /* 控制间隔100ms */
    sg_pLedTable[led].proc.tic = 0;                                             /* 清零计时器 */
    sg_pLedTable[led].proc.data.state[0] = (state == COT_LED_ON ? 0x01 : 0x00); /* 设置LED状态 */
    sg_pLedTable[led].proc.offset = 0;                                          /* 状态位偏移清零 */
    sg_pLedTable[led].proc.validBits = 1;                                       /* 只有1个有效状态位 */
    sg_pLedTable[led].proc.count = 0;                                           /* 无次数限制 */
    sg_pLedTable[led].proc.isSetCount = 0;                                      /* 未设置次数 */
    sg_pLedTable[led].proc.defState = 0;                                        /* 默认状态为灭 */
    sg_pLedTable[led].proc.isPwm = 0;                                           /* 非PWM模式 */
    return 0;
}

/**
 * @brief      设置LED的亮灭状态及持续时间
 *
 * @attention  时间应为控制任务调度周期的倍数
 *
 * @param[in]  led       指定指示灯
 * @param[in]  state     亮灭状态
 *             @arg      COT_LED_ON  LED点亮
 *             @arg      COT_LED_OFF LED熄灭
 * @param[in]  time      持续时间,单位毫秒,到达时间后LED会自动熄灭
 *
 * @note       该函数设置LED为固定状态,并在指定时间后自动熄灭
 *             例如:设置LED亮1000ms,则LED会亮1秒后自动熄灭
 *
 * @retval     0         成功
 * @retval     -1        失败
 */
int cotLed_SetStateWithTime(led_t led, cotLedState_e state, uint16_t time)
{
    /* 参数有效性检查 */
    if (sg_pLedTable == NULL || sg_ledNum == 0 || led >= sg_ledNum)
    {
        return -1;
    }

    /* 设置LED控制参数 */
    sg_pLedTable[led].proc.interval = time;                                     /* 持续时间 */
    sg_pLedTable[led].proc.tic = 0;                                             /* 清零计时器 */
    sg_pLedTable[led].proc.data.state[0] = (state == COT_LED_ON ? 0x01 : 0x00); /* 设置LED状态 */
    sg_pLedTable[led].proc.offset = 0;                                          /* 状态位偏移清零 */
    sg_pLedTable[led].proc.validBits = 1;                                       /* 只有1个有效状态位 */
    sg_pLedTable[led].proc.count = 1;                                           /* 只执行1次 */
    sg_pLedTable[led].proc.isSetCount = 1;                                      /* 设置了次数 */
    sg_pLedTable[led].proc.defState = (state == COT_LED_ON ? 0 : 1);            /* 结束后的状态与当前状态相反 */
    sg_pLedTable[led].proc.isPwm = 0;                                           /* 非PWM模式 */

    return 0;
}

/**
 * @brief      点亮LED
 *
 * @param[in]  led       指定指示灯
 *
 * @note       该函数是cotLed_SetState的简化版本
 *             等价于cotLed_SetState(led, COT_LED_ON)
 *
 * @retval     0         成功
 * @retval     -1        失败
 */
int cotLed_ON(led_t led)
{
    return cotLed_SetState(led, COT_LED_ON);
}

/**
 * @brief      熄灭LED
 *
 * @param[in]  led       指定指示灯
 *
 * @note       该函数是cotLed_SetState的简化版本
 *             等价于cotLed_SetState(led, COT_LED_OFF)
 *
 * @retval     0         成功
 * @retval     -1        失败
 */
int cotLed_OFF(led_t led)
{
    return cotLed_SetState(led, COT_LED_OFF);
}

/**
 * @brief      翻转指定LED亮灭状态
 *
 * @param[in]  led       指定指示灯
 *
 * @note       如果LED当前是亮的则熄灭,如果是灭的则点亮
 *
 * @retval     0         成功
 * @retval     -1        失败
 */
int cotLed_Toggle(led_t led)
{
    /* 参数有效性检查 */
    if (sg_pLedTable == NULL || sg_ledNum == 0 || led >= sg_ledNum)
    {
        return -1;
    }

    /* 设置LED控制参数 */
    sg_pLedTable[led].proc.interval = 100; /* 控制间隔100ms */
    sg_pLedTable[led].proc.tic = 0;        /* 清零计时器 */
    /* 当前状态取反 */
    sg_pLedTable[led].proc.data.state[0] = sg_pLedTable[led].proc.data.state[0] == 0 ? 0x01 : 0x00;
    sg_pLedTable[led].proc.offset = 0;     /* 状态位偏移清零 */
    sg_pLedTable[led].proc.validBits = 1;  /* 只有1个有效状态位 */
    sg_pLedTable[led].proc.count = 0;      /* 无次数限制 */
    sg_pLedTable[led].proc.isSetCount = 0; /* 未设置次数 */
    sg_pLedTable[led].proc.defState = 0;   /* 默认状态为灭 */
    sg_pLedTable[led].proc.isPwm = 0;      /* 非PWM模式 */

    return 0;
}

/**
 * @brief      设置LED为闪烁状态
 *
 * @attention  时间应为控制任务调度周期的倍数
 *
 * @param[in]  led       指定指示灯
 * @param[in]  time      闪烁亮灭间隔时间, 单位毫秒
 *
 * @note       LED会以相同的时间间隔交替亮灭
 *             例如time=500时,LED会每500ms改变一次状态
 *
 * @retval     0         成功
 * @retval     -1        失败
 */
int cotLed_Twinkle(led_t led, uint16_t time)
{
    /* 参数有效性检查 */
    if (sg_pLedTable == NULL || sg_ledNum == 0 || led >= sg_ledNum)
    {
        return -1;
    }

    /* 设置LED闪烁参数 */
    sg_pLedTable[led].proc.interval = time;      /* 设置闪烁间隔 */
    sg_pLedTable[led].proc.tic = 0;              /* 清零计时器 */
    sg_pLedTable[led].proc.data.state[0] = 0x01; /* 初始状态为亮 */
    sg_pLedTable[led].proc.offset = 0;           /* 状态位偏移清零 */
    sg_pLedTable[led].proc.validBits = 2;        /* 2个状态位表示亮灭 */
    sg_pLedTable[led].proc.count = 0;            /* 无次数限制 */
    sg_pLedTable[led].proc.isSetCount = 0;       /* 未设置次数 */
    sg_pLedTable[led].proc.defState = 0;         /* 默认状态为灭 */
    sg_pLedTable[led].proc.isPwm = 0;            /* 非PWM模式 */

    return 0;
}

/**
 * @brief      设置LED为闪烁状态及次数,最后次数完成后的亮灭状态
 *
 * @attention  时间应为控制任务调度周期的倍数
 *
 * @param[in]  led       指定指示灯
 * @param[in]  time      闪烁亮灭间隔时间,单位毫秒
 * @param[in]  count     闪烁次数,一亮一灭算一次
 * @param[in]  defState  闪烁次数完成后的亮灭状态
 *             @arg      COT_LED_ON  LED点亮
 *             @arg      COT_LED_OFF LED熄灭
 *
 * @note       该函数与cotLed_Twinkle的区别是可以设置闪烁次数
 *             例如:设置LED以500ms间隔闪烁3次,完成后保持点亮
 *             则LED会:亮->灭->亮->灭->亮->灭->亮(保持)
 *
 * @retval     0         成功
 * @retval     -1        失败
 */
int cotLed_TwinkleWithCount(led_t led, uint16_t time, uint8_t count, cotLedState_e defState)
{
    /* 参数有效性检查 */
    if (sg_pLedTable == NULL || sg_ledNum == 0 || led >= sg_ledNum)
    {
        return -1;
    }

    /* 设置LED闪烁参数 */
    sg_pLedTable[led].proc.interval = time; /* 闪烁间隔 */
    sg_pLedTable[led].proc.tic = 0;         /* 清零计时器 */
    /* 根据默认状态设置初始状态,使最后一次闪烁结束时正好是默认状态 */
    sg_pLedTable[led].proc.data.state[0] = defState == COT_LED_ON ? 0x01 : 0x02;
    sg_pLedTable[led].proc.offset = 0;                                /* 状态位偏移清零 */
    sg_pLedTable[led].proc.validBits = 2;                             /* 2个状态位表示亮灭 */
    sg_pLedTable[led].proc.count = count;                             /* 设置闪烁次数 */
    sg_pLedTable[led].proc.isSetCount = 1;                            /* 设置了次数 */
    sg_pLedTable[led].proc.defState = defState == COT_LED_ON ? 1 : 0; /* 结束后的状态 */
    sg_pLedTable[led].proc.isPwm = 0;                                 /* 非PWM模式 */

    return 0;
}

/**
 * @brief      为多个LED设置为跑马灯
 *
 * @param[in]  led       LED组数组
 * @param[in]  ledNum    LED数目
 * @param[in]  time      每个LED亮的持续时间,单位毫秒
 *
 * @note       跑马灯效果:LED依次点亮,每次只有一个LED亮
 *             例如:3个LED的跑马灯效果
 *             LED1: 亮->灭->灭->亮->灭->灭->...
 *             LED2: 灭->亮->灭->灭->亮->灭->...
 *             LED3: 灭->灭->亮->灭->灭->亮->...
 *
 * @retval     0         成功
 * @retval     -1        失败
 */
int cotLed_Marquee(led_t led[], uint8_t ledNum, int32_t time)
{
    /* 参数有效性检查 */
    if (sg_pLedTable == NULL || sg_ledNum == 0)
    {
        return -1;
    }

    /* 设置每个LED的跑马灯参数 */
    for (uint8_t i = 0; i < ledNum; i++)
    {
        if (led[i] < sg_ledNum)
        {
            /* 清空状态位数组 */
            memset(sg_pLedTable[led[i]].proc.data.state, 0, LED_STATE_BYTE_NUM);

            sg_pLedTable[led[i]].proc.interval = time; /* 设置时间间隔 */
            sg_pLedTable[led[i]].proc.tic = 0;         /* 清零计时器 */

            /* 设置状态位:只在当前LED对应的位置为1 */
            SET_STATE_BITS(sg_pLedTable[led[i]].proc.data.state, i);

            sg_pLedTable[led[i]].proc.offset = 0;         /* 状态位偏移清零 */
            sg_pLedTable[led[i]].proc.validBits = ledNum; /* 有效位数为LED数 */
            sg_pLedTable[led[i]].proc.count = 0;          /* 无次数限制 */
            sg_pLedTable[led[i]].proc.isSetCount = 0;     /* 未设置次数 */
            sg_pLedTable[led[i]].proc.defState = 0;       /* 默认状态为灭 */
            sg_pLedTable[led[i]].proc.isPwm = 0;          /* 非PWM模式 */
        }
    }

    return 0;
}

/**
 * @brief      为多个LED设置为跑马灯及次数,最后次数完成后的亮灭状态
 *
 * @param[in]  led       LED组数组
 * @param[in]  ledNum    LED数目
 * @param[in]  time      每个LED亮的持续时间,单位毫秒
 * @param[in]  count     跑马灯循环次数,一轮算一次
 * @param[in]  defState  跑马灯次数完成后的亮灭状态
 *             @arg      COT_LED_ON  LED点亮
 *             @arg      COT_LED_OFF LED熄灭
 *
 * @note       该函数与cotLed_Marquee的区别是可以设置循环次数
 *             和结束后的LED状态
 *
 * @retval     0         成功
 * @retval     -1        失败
 */
int cotLed_MarqueeWithCount(led_t led[], uint8_t ledNum, int32_t time, uint8_t count, cotLedState_e defState)
{
    /* 参数有效性检查 */
    if (sg_pLedTable == NULL || sg_ledNum == 0)
    {
        return -1;
    }

    /* 设置每个LED的跑马灯参数 */
    for (uint8_t i = 0; i < ledNum; i++)
    {
        if (led[i] < sg_ledNum)
        {
            /* 清空状态位数组 */
            memset(sg_pLedTable[led[i]].proc.data.state, 0, LED_STATE_BYTE_NUM);

            sg_pLedTable[led[i]].proc.interval = time; /* 设置时间间隔 */
            sg_pLedTable[led[i]].proc.tic = 0;         /* 清零计时器 */

            /* 设置状态位:只在当前LED对应的位置为1 */
            SET_STATE_BITS(sg_pLedTable[led[i]].proc.data.state, i);

            sg_pLedTable[led[i]].proc.offset = 0;                                /* 状态位偏移清零 */
            sg_pLedTable[led[i]].proc.validBits = ledNum;                        /* 有效位数为LED数 */
            sg_pLedTable[led[i]].proc.count = count;                             /* 设置循环次数 */
            sg_pLedTable[led[i]].proc.isSetCount = 1;                            /* 设置了次数 */
            sg_pLedTable[led[i]].proc.defState = defState == COT_LED_ON ? 1 : 0; /* 结束后的状态 */
            sg_pLedTable[led[i]].proc.isPwm = 0;                                 /* 非PWM模式 */
        }
    }

    return 0;
}

/**
 * @brief      为多个LED设置为流水灯
 *
 * @param[in]  led       LED组数组
 * @param[in]  ledNum    LED数目
 * @param[in]  time      每个LED亮的持续时间,单位毫秒
 *
 * @note       流水灯效果:LED依次点亮,形成流水的效果
 *             与跑马灯的区别是:流水灯可以同时点亮多个LED
 *
 * @retval     0         成功
 * @retval     -1        失败
 */
int cotLed_Waterfall(led_t led[], uint8_t ledNum, int32_t time)
{
    /* 参数有效性检查 */
    if (sg_pLedTable == NULL || sg_ledNum == 0)
    {
        return -1;
    }

    /* 设置每个LED的流水灯参数 */
    for (uint8_t i = 0; i < ledNum; i++)
    {
        if (led[i] < sg_ledNum)
        {
            /* 清空状态位数组 */
            memset(sg_pLedTable[led[i]].proc.data.state, 0, LED_STATE_BYTE_NUM);

            sg_pLedTable[led[i]].proc.interval = time; /* 设置时间间隔 */
            sg_pLedTable[led[i]].proc.tic = 0;         /* 清零计时器 */

            /* 设置状态位:从当前LED开始到最后一个LED都为1 */
            FILL_STATE_BITS(sg_pLedTable[led[i]].proc.data.state, i, ledNum);

            sg_pLedTable[led[i]].proc.offset = 0;             /* 状态位偏移清零 */
            sg_pLedTable[led[i]].proc.validBits = ledNum + 1; /* 有效位数为LED数+1 */
            sg_pLedTable[led[i]].proc.count = 0;              /* 无次数限制 */
            sg_pLedTable[led[i]].proc.isSetCount = 0;         /* 未设置次数 */
            sg_pLedTable[led[i]].proc.defState = 0;           /* 默认状态为灭 */
            sg_pLedTable[led[i]].proc.isPwm = 0;              /* 非PWM模式 */
        }
    }

    return 0;
}

/**
 * @brief      为多个LED设置为流水灯及次数, 最后次数完成后的亮灭状态
 *
 * @param[in]  led       LED组数组
 * @param[in]  ledNum    LED数目
 * @param[in]  time      每个LED亮的持续时间,单位毫秒
 * @param[in]  count     流水灯循环次数,一轮算一次
 * @param[in]  defState  流水灯次数完成后的亮灭状态
 *             @arg      COT_LED_ON  LED点亮
 *             @arg      COT_LED_OFF LED熄灭
 *
 * @note       该函数与cotLed_Waterfall的区别是可以设置循环次数
 *             和结束后的LED状态
 *
 * @retval     0         成功
 * @retval     -1        失败
 */
int cotLed_WaterfallWithCount(led_t led[], uint8_t ledNum, int32_t time, uint8_t count, cotLedState_e defState)
{
    /* 参数有效性检查 */
    if (sg_pLedTable == NULL || sg_ledNum == 0)
    {
        return -1;
    }

    /* 设置每个LED的流水灯参数 */
    for (uint8_t i = 0; i < ledNum; i++)
    {
        if (led[i] < sg_ledNum)
        {
            /* 清空状态位数组 */
            memset(sg_pLedTable[led[i]].proc.data.state, 0, LED_STATE_BYTE_NUM);

            sg_pLedTable[led[i]].proc.interval = time; /* 设置时间间隔 */
            sg_pLedTable[led[i]].proc.tic = 0;         /* 清零计时器 */

            /* 设置状态位:从当前LED开始到最后一个LED都为1 */
            FILL_STATE_BITS(sg_pLedTable[led[i]].proc.data.state, i, ledNum);

            sg_pLedTable[led[i]].proc.offset = 0;                                /* 状态位偏移清零 */
            sg_pLedTable[led[i]].proc.validBits = ledNum + 1;                    /* 有效位数为LED数+1 */
            sg_pLedTable[led[i]].proc.count = count;                             /* 设置循环次数 */
            sg_pLedTable[led[i]].proc.isSetCount = 1;                            /* 设置了次数 */
            sg_pLedTable[led[i]].proc.defState = defState == COT_LED_ON ? 1 : 0; /* 结束后的状态 */
            sg_pLedTable[led[i]].proc.isPwm = 0;                                 /* 非PWM模式 */
        }
    }

    return 0;
}

/**
 * @brief      设置指定LED为呼吸灯模式
 *
 * @attention  LED控制任务必须为1ms周期,否则PWM效果会不准确
 *
 * @param[in]  led       指定指示灯
 * @param[in]  period    呼吸周期,即完成一次由暗到亮再到暗的时间,单位毫秒
 *
 * @note       呼吸灯使用软件PWM实现,通过调节PWM占空比产生渐变效果
 *             PWM频率为BREATHE_PWM_RATE(默认50Hz)
 *
 * @retval     0         成功
 * @retval     -1        失败
 */
int cotLed_Breathe(led_t led, uint16_t period)
{
    /* 参数有效性检查 */
    if (sg_pLedTable == NULL || sg_ledNum == 0)
    {
        return -1;
    }

    if (led < sg_ledNum)
    {
        /* 计算PWM参数更新间隔 */
        /* period/2是半个周期(即亮到暗的时间) */
        /* 除以BREATHE_PWM_PERIOD是为了将半个周期分成PWM周期数个等份 */
        sg_pLedTable[led].proc.interval = period / 2 / BREATHE_PWM_PERIOD;
        sg_pLedTable[led].proc.tic = 0;
        sg_pLedTable[led].proc.data.state[0] = 0; /* 根据默认状态最后一次闪烁时状态设置相反状态达到较好的闪烁效果 */
        sg_pLedTable[led].proc.offset = 0;
        sg_pLedTable[led].proc.validBits = 2;
        sg_pLedTable[led].proc.count = 0;           /* 无次数限制 */
        sg_pLedTable[led].proc.isSetCount = 0;      /* 未设置次数 */
        sg_pLedTable[led].proc.defState = 0;        /* 默认状态为灭 */
        sg_pLedTable[led].proc.isPwm = 1;           /* 使用PWM模式 */
        sg_pLedTable[led].proc.data.pwm.onTime = 0; /* PWM初始占空比为0 */
        sg_pLedTable[led].proc.data.pwm.tic = 0;    /* PWM计时器清零 */
        sg_pLedTable[led].proc.pwmDir = 1;          /* PWM占空比递增方向 */
    }

    return 0;
}

/**
 * @brief      设置指定LED为呼吸灯模式及次数,最后次数完成后的亮灭状态
 *
 * @attention  LED控制任务必须为1ms周期
 *
 * @param[in]  led       指定指示灯
 * @param[in]  period    呼吸周期，即多久完成一次呼吸；单位毫秒
 * @param[in]  count     呼吸次数
 * @param[in]  defState  呼吸次数完成后的亮灭状态
 *             @arg      COT_LED_ON  LED点亮
 *             @arg      COT_LED_OFF LED熄灭
 *
 * @note       该函数与cotLed_Breathe的区别是可以设置呼吸次数
 *             例如:设置LED以2秒为周期呼吸3次,最后保持点亮
 *             cotLed_BreatheWithCount(LED_0, 2000, 3, COT_LED_ON);
 *
 * @retval     0         成功
 * @retval     -1        失败
 */
int cotLed_BreatheWithCount(led_t led, uint16_t period, uint8_t count, cotLedState_e defState)
{
    /* 参数有效性检查 */
    if (sg_pLedTable == NULL || sg_ledNum == 0)
    {
        return -1;
    }

    if (led < sg_ledNum)
    {
        /* 计算PWM参数更新间隔 */
        /* period/2是半个周期(即亮到暗的时间) */
        /* 除以BREATHE_PWM_PERIOD是为了将半个周期分成PWM周期数个等份 */
        sg_pLedTable[led].proc.interval = period / 2 / BREATHE_PWM_PERIOD;
        sg_pLedTable[led].proc.tic = 0;
        sg_pLedTable[led].proc.data.state[0] = 0; /* 根据默认状态最后一次闪烁时状态设置相反状态达到较好的闪烁效果 */
        sg_pLedTable[led].proc.offset = 0;
        sg_pLedTable[led].proc.validBits = 2;
        sg_pLedTable[led].proc.count = count;                             /* 设置呼吸次数 */
        sg_pLedTable[led].proc.isSetCount = 1;                            /* 设置了次数 */
        sg_pLedTable[led].proc.defState = defState == COT_LED_ON ? 1 : 0; /* 结束后的状态 */
        sg_pLedTable[led].proc.isPwm = 1;                                 /* 使用PWM模式 */
        sg_pLedTable[led].proc.data.pwm.onTime = 0;                       /* PWM初始占空比为0 */
        sg_pLedTable[led].proc.data.pwm.tic = 0;                          /* PWM计时器清零 */
        sg_pLedTable[led].proc.pwmDir = 1;                                /* PWM占空比递增方向 */
    }

    return 0;
}

/**
 * @brief      设置LED的自定义状态
 *
 * @attention  时间应为控制任务调度周期的倍数
 *
 * @param[in]  led       指定指示灯
 * @param[in]  ...       亮灭时间参数：
 *                       > 0, 亮的持续时间
 *                       < 0, 灭的持续时间
 *                       = 0, 可变参数设置结束
 *
 * @note       该函数可以设置LED的自定义亮灭序列
 *             例如:设置LED在2秒内快闪3次
 *             cotLed_Custom(LED_0, 100, -100, 100, -100, 100, -1400, 0);
 *             参数含义:亮100ms->灭100ms->亮100ms->灭100ms->亮100ms->灭1400ms
 *
 * @retval     0         成功
 * @retval     -1        失败
 */
int cotLed_Custom(led_t led, ...)
{
    uint8_t bits;
    uint8_t offset = 0;
    uint8_t validBits = 0;
    va_list timeList;
    int32_t time;
    uint16_t interval = 0xffff;

    /* 参数有效性检查 */
    if (sg_pLedTable == NULL || sg_ledNum == 0 || led >= sg_ledNum)
    {
        return -1;
    }

    /* 第一次遍历参数,找出最小的时间间隔 */
    va_start(timeList, led);
    do
    {
        time = va_arg(timeList, int32_t);

        /* 找出非0参数中最小的时间间隔 */
        if (time != 0 && LED_ABS(time) < interval)
        {
            interval = (uint16_t)LED_ABS(time);
        }
    } while (time != 0);

    va_end(timeList);

    /* 初始化状态位数组 */
    validBits = 0;
    offset = 0;
    memset(sg_pLedTable[led].proc.data.state, 0, sizeof(sg_pLedTable[led].proc.data.state));

    /* 第二次遍历参数,设置状态位 */
    va_start(timeList, led);
    do
    {
        time = va_arg(timeList, int32_t);

        if (LED_ABS(time) != 0)
        {
            /* 计算当前时间需要多少个最小间隔 */
            bits = (uint16_t)LED_ABS(time) / interval;

            if (time > 0) /* 正数表示亮 */
            {
                /* 连续设置bits个1 */
                for (int i = 0; i < bits; i++)
                {
                    sg_pLedTable[led].proc.data.state[offset / 8] |= 0x01 << (offset % 8);
                    offset++;
                }
            }
            else /* 负数表示灭 */
            {
                /* 连续设置bits个0 */
                for (int i = 0; i < bits; i++)
                {
                    sg_pLedTable[led].proc.data.state[offset / 8] |= 0x00 << (offset % 8);
                    offset++;
                }
            }

            validBits += bits; /* 累加有效位数 */
        }
    } while (time != 0);

    va_end(timeList);

    /* 设置LED控制参数 */
    sg_pLedTable[led].proc.interval = interval;   /* 使用最小的时间间隔 */
    sg_pLedTable[led].proc.tic = 0;               /* 清零计时器 */
    sg_pLedTable[led].proc.offset = 0;            /* 状态位偏移清零 */
    sg_pLedTable[led].proc.validBits = validBits; /* 设置有效位数 */
    sg_pLedTable[led].proc.count = 0;             /* 无次数限制 */
    sg_pLedTable[led].proc.isSetCount = 0;        /* 未设置次数 */
    sg_pLedTable[led].proc.defState = 0;          /* 默认状态为灭 */
    sg_pLedTable[led].proc.isPwm = 0;             /* 非PWM模式 */

    return 0;
}

/**
 * @brief      设置LED的自定义状态及次数,最后次数完成后的亮灭状态
 *
 * @attention  时间应为控制任务调度周期的倍数
 *
 * @param[in]  led       指定指示灯
 * @param[in]  count     自定义状态次数,0表示无次数限制
 * @param[in]  defState  自定义状态次数完成后的亮灭状态
 *             @arg      COT_LED_ON  LED点亮
 *             @arg      COT_LED_OFF LED熄灭
 * @param[in]  ...       亮灭时间参数：
 *                       > 0, 亮的持续时间
 *                       < 0, 灭的持续时间
 *                       = 0, 可变参数设置结束
 *
 * @note       该函数与cotLed_Custom的区别是可以设置循环次数
 *             例如:设置LED在2秒内快闪3次,总共5次,最后熄灭
 *             cotLed_CustomWithCount(LED_0, 5, COT_LED_OFF,
 *                                  100, -100, 100, -100, 100, -1400, 0);
 *
 * @retval     0         成功
 * @retval     -1        失败
 */
int cotLed_CustomWithCount(led_t led, uint8_t count, cotLedState_e defState, ...)
{
    uint8_t bits;
    uint8_t offset = 0;
    uint8_t validBits = 0;
    va_list timeList;
    int32_t time;
    uint16_t interval = 0xffff;

    /* 参数有效性检查 */
    if (sg_pLedTable == NULL || sg_ledNum == 0 || led >= sg_ledNum)
    {
        return -1;
    }

    /* 第一次遍历参数,找出最小的时间间隔 */
    va_start(timeList, defState);
    do
    {
        time = va_arg(timeList, int32_t);

        /* 找出非0参数中最小的时间间隔 */
        if (time != 0 && LED_ABS(time) < interval)
        {
            interval = (uint16_t)LED_ABS(time);
        }
    } while (time != 0);
    va_end(timeList);

    /* 初始化状态位数组 */
    validBits = 0;
    offset = 0;
    memset(sg_pLedTable[led].proc.data.state, 0, sizeof(sg_pLedTable[led].proc.data.state));

    /* 第二次遍历参数,设置状态位 */
    va_start(timeList, defState);
    do
    {
        time = va_arg(timeList, int32_t);

        if (LED_ABS(time) != 0)
        {
            /* 计算当前时间需要多少个最小间隔 */
            bits = (uint16_t)LED_ABS(time) / interval;

            if (time > 0) /* 正数表示亮 */
            {
                /* 连续设置bits个1 */
                for (int i = 0; i < bits; i++)
                {
                    sg_pLedTable[led].proc.data.state[offset / 8] |= 0x01 << (offset % 8);
                    offset++;
                }
            }
            else /* 负数表示灭 */
            {
                /* 连续设置bits个0 */
                for (int i = 0; i < bits; i++)
                {
                    sg_pLedTable[led].proc.data.state[offset / 8] |= 0x00 << (offset % 8);
                    offset++;
                }
            }

            validBits += bits; /* 累加有效位数 */
        }
    } while (time != 0);

    va_end(timeList);

    /* 设置LED控制参数 */
    sg_pLedTable[led].proc.interval = interval;                       /* 使用最小的时间间隔 */
    sg_pLedTable[led].proc.tic = 0;                                   /* 清零计时器 */
    sg_pLedTable[led].proc.offset = 0;                                /* 状态位偏移清零 */
    sg_pLedTable[led].proc.validBits = validBits;                     /* 设置有效位数 */
    sg_pLedTable[led].proc.count = count;                             /* 设置循环次数 */
    sg_pLedTable[led].proc.isSetCount = count == 0 ? 0 : 1;           /* 根据count决定是否设置次数 */
    sg_pLedTable[led].proc.defState = defState == COT_LED_ON ? 1 : 0; /* 结束后的状态 */
    sg_pLedTable[led].proc.isPwm = 0;                                 /* 非PWM模式 */

    return 0;
}

/**
 * @brief      读取当前PWM状态
 *
 * @param[in]  pLed      LED控制结构体指针
 *
 * @note       根据PWM计时器和占空比计算当前应该是亮还是灭
 *             用于实现呼吸灯效果
 *
 * @retval     COT_LED_ON   LED应该处于亮状态
 * @retval     COT_LED_OFF  LED应该处于灭状态
 */
static cotLedState_e ReadPwmLedState(cotLedProc_t *pLed)
{
    cotLedState_e eLedState;

    /* 如果当前时间小于亮的时间,则LED应该亮 */
    if (pLed->data.pwm.tic < pLed->data.pwm.onTime)
    {
        eLedState = COT_LED_ON;
    }
    else
    {
        eLedState = COT_LED_OFF;
    }

    /* PWM周期结束,重新开始计时 */
    if (pLed->data.pwm.tic >= BREATHE_PWM_PERIOD)
    {
        pLed->data.pwm.tic = 0;
    }

    return eLedState;
}

/**
 * @brief      控制PWM占空比变化
 *
 * @param[in]  pLed      LED控制结构体指针
 *
 * @note       根据pwmDir控制占空比递增或递减
 *             用于实现呼吸灯效果
 */
static void CtrlPwmLedState(cotLedProc_t *pLed)
{
    /* 到达更新间隔时间 */
    if (pLed->tic > pLed->interval)
    {
        pLed->tic = 0;

        if (pLed->pwmDir) /* 占空比递增 */
        {
            pLed->data.pwm.onTime++;

            /* 达到最大占空比,改为递减 */
            if (pLed->data.pwm.onTime >= BREATHE_PWM_PERIOD)
            {
                pLed->pwmDir = 0;
            }
        }
        else /* 占空比递减 */
        {
            pLed->data.pwm.onTime--;

            /* 达到最小占空比,改为递增 */
            if (pLed->data.pwm.onTime == 0)
            {
                pLed->pwmDir = 1;

                /* 完成一次呼吸周期,计数减1 */
                if (pLed->count > 0)
                {
                    pLed->count--;
                }
            }
        }
    }
}

/**
 * @brief      LED控制周期任务
 *
 * @param[in]  sysTime   系统运行时间,单位毫秒
 *
 * @note       该函数需要周期调用,推荐的调用周期:
 *             - 普通控制模式: 20ms
 *             - 呼吸灯模式: 1ms
 *
 * @retval     0         成功
 * @retval     -1        失败
 */
int cotLed_Ctrl(uint32_t sysTime)
{
    uint16_t led;
    static uint32_t s_sysTimeBak = 0; /* 上次调用时的系统时间 */

    /* 参数有效性检查 */
    if (sg_pLedTable == NULL || sg_ledNum == 0)
    {
        return -1;
    }

    /* 首次调用,初始化时间 */
    if (s_sysTimeBak == 0)
    {
        s_sysTimeBak = sysTime;
    }

    /* 遍历所有LED,更新它们的状态 */
    for (led = 0; led < sg_ledNum; led++)
    {
        /* 更新计时器 */
        TIME_ADD(sg_pLedTable[led].proc.tic, (sysTime - s_sysTimeBak));

        /* 如果设置了次数 */
        if (sg_pLedTable[led].proc.isSetCount)
        {
            if (sg_pLedTable[led].proc.count == 0) /* 次数用完 */
            {
                /* 使用默认状态 */
                sg_pLedTable[led].proc.curState = sg_pLedTable[led].proc.defState ? COT_LED_ON : COT_LED_OFF;
            }
            else /* 还有剩余次数 */
            {
                if (sg_pLedTable[led].proc.isPwm) /* PWM模式 */
                {
                    /* 读取PWM当前状态 */
                    sg_pLedTable[led].proc.curState = ReadPwmLedState(&sg_pLedTable[led].proc);
                }
                else /* 普通模式 */
                {
                    /* 从状态位数组中读取当前状态 */
                    sg_pLedTable[led].proc.curState = (cotLedState_e)((sg_pLedTable[led].proc.data.state[sg_pLedTable[led].proc.offset / 8] >> (sg_pLedTable[led].proc.offset % 8)) & 0X01);
                }
            }
        }
        else /* 未设置次数,永久运行 */
        {
            if (sg_pLedTable[led].proc.isPwm) /* PWM模式 */
            {
                /* 读取PWM当前状态 */
                sg_pLedTable[led].proc.curState = ReadPwmLedState(&sg_pLedTable[led].proc);
            }
            else /* 普通模式 */
            {
                /* 从状态位数组中读取当前状态 */
                sg_pLedTable[led].proc.curState = (cotLedState_e)((sg_pLedTable[led].proc.data.state[sg_pLedTable[led].proc.offset / 8] >> (sg_pLedTable[led].proc.offset % 8)) & 0X01);
            }
        }

        /* PWM模式特殊处理 */
        if (sg_pLedTable[led].proc.isPwm)
        {
            /* 更新PWM计时器 */
            TIME_ADD(sg_pLedTable[led].proc.data.pwm.tic, (sysTime - s_sysTimeBak));
            /* 控制PWM占空比变化 */
            CtrlPwmLedState(&sg_pLedTable[led].proc);
        }
        else /* 普通模式 */
        {
            /* 到达状态切换时间 */
            if (sg_pLedTable[led].proc.tic >= sg_pLedTable[led].proc.interval)
            {
                sg_pLedTable[led].proc.tic = 0;  /* 清零计时器 */
                sg_pLedTable[led].proc.offset++; /* 移动到下一个状态位 */

                /* 所有状态位都已使用完 */
                if (sg_pLedTable[led].proc.offset >= sg_pLedTable[led].proc.validBits)
                {
                    sg_pLedTable[led].proc.offset = 0; /* 重新开始 */

                    /* 如果设置了次数,则减1 */
                    if (sg_pLedTable[led].proc.count > 0)
                    {
                        sg_pLedTable[led].proc.count--;
                    }
                }
            }
        }
    }

    /* 调用每个LED的控制函数,更新实际的LED状态 */
    for (led = 0; led < sg_ledNum; led++)
    {
        sg_pLedTable[led].pfnLedCtrl(sg_pLedTable[led].proc.curState ? COT_LED_ON : COT_LED_OFF);
    }

    /* 保存这次的系统时间 */
    s_sysTimeBak = sysTime;

    return 0;
}
